using System.ComponentModel;
using System.Runtime.Serialization;

using SharpGL.Enumerations;

namespace SharpGL.OpenGLAttributes
{
	/// <summary>
	/// This class has all the settings you can edit for viewport.
	/// </summary>
	[TypeConverter(typeof(System.ComponentModel.ExpandableObjectConverter))]
    [DataContract(/*IsReference = true, */Name = "ViewportAttributes", Namespace = "SharpGL.SceneGraph")]
    public class ViewportAttributes : OpenGLAttributes
	{
        #region Private Consts

        private static readonly AttributeMask attributeMask = AttributeMask.Viewport;

        #endregion Private Consts

        #region Private Fields

        [DataMember()]
        private int? viewportX;
        [DataMember()]
        private int? viewportY;
        [DataMember()]
        private int? viewportWidth;
        [DataMember()]
        private int? viewportHeight;
        [DataMember()]
        private double? depthRangeNear;
        [DataMember()]
        private double? depthRangeFar;

        #endregion Private Fields

        #region Protected Methods

        protected override void OnDeserializing()
        {
            AttributeFlags = attributeMask;
        }

        #endregion Protected Methods

        #region Public Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="ViewportAttributes"/> class.
        /// </summary>
        public ViewportAttributes()
        {
            AttributeFlags = attributeMask;
        }

        #endregion Public Constructors

        #region Public Methods

        /// <summary>
        /// Returns true if any attributes are set.
        /// </summary>
        /// <returns>
        /// True if any attributes are set
        /// </returns>
        public override bool AreAnyAttributesSet()
        {
            return
                viewportX.HasValue ||
                viewportY.HasValue ||
                viewportWidth.HasValue ||
                viewportHeight.HasValue ||
                depthRangeNear.HasValue ||
                depthRangeFar.HasValue;
        }

        /// <summary>
        /// Reset all attributes to unset state.
        /// </summary>
        public override void ResetAllAttributes()
        {
            viewportX = null;
            viewportY = null;
            viewportWidth = null;
            viewportHeight = null;
            depthRangeNear = null;
            depthRangeFar = null;
        }

        /// <summary>
        /// Sets the attributes.
        /// </summary>
        /// <param name="gl">The OpenGL instance.</param>
        public override void SetAttributes(OpenGL gl)
        {
            if (viewportX.HasValue && viewportY.HasValue && viewportWidth.HasValue && viewportHeight.HasValue)
                gl.Viewport(viewportX.Value, viewportY.Value, viewportWidth.Value, viewportHeight.Value);
            if (depthRangeNear.HasValue && depthRangeFar.HasValue)
                gl.DepthRange(depthRangeNear.Value, depthRangeFar.Value);
        }

        #endregion Public Methods

        #region Public Properties

        /// <summary>
        /// Gets or sets the viewport X.
        /// </summary>
        /// <value>
        /// The viewport X.
        /// </value>
        [Description("ViewportX"), Category("Viewport attributes")]
        public int? ViewportX
        {
            get { return viewportX; }
            set
            {
                if (viewportX != value)
                {
                    viewportX = value;

                    NotifyPropertyChanged("ViewportX");
                }
            }
        }

        /// <summary>
        /// Gets or sets the viewport Y.
        /// </summary>
        /// <value>
        /// The viewport Y.
        /// </value>
        [Description("ViewportY"), Category("Viewport attributes")]
        public int? ViewportY
        {
            get { return viewportY; }
            set
            {
                if (viewportY != value)
                {
                    viewportY = value;

                    NotifyPropertyChanged("ViewportY");
                }
            }
        }

        /// <summary>
        /// Gets or sets the width of the viewport.
        /// </summary>
        /// <value>
        /// The width of the viewport.
        /// </value>
        [Description("ViewportWidth"), Category("Viewport attributes")]
        public int? ViewportWidth
        {
            get { return viewportWidth; }
            set
            {
                if (viewportWidth != value)
                {
                    viewportWidth = value;

                    NotifyPropertyChanged("ViewportWidth");
                }
            }
        }

        /// <summary>
        /// Gets or sets the height of the viewport.
        /// </summary>
        /// <value>
        /// The height of the viewport.
        /// </value>
        [Description("ViewportHeight"), Category("Viewport attributes")]
        public int? ViewportHeight
        {
            get { return viewportHeight; }
            set
            {
                if (viewportHeight != value)
                {
                    viewportHeight = value;

                    NotifyPropertyChanged("ViewportHeight");
                }
            }
        }

        /// <summary>
        /// Gets or sets the depth range near.
        /// </summary>
        /// <value>
        /// The depth range near.
        /// </value>
        [Description("DepthRangeNear"), Category("Viewport attributes")]
        public double? DepthRangeNear
        {
            get { return depthRangeNear; }
            set
            {
                if (depthRangeNear != value)
                {
                    depthRangeNear = value;

                    NotifyPropertyChanged("DepthRangeNear");
                }
            }
        }

        /// <summary>
        /// Gets or sets the depth range far.
        /// </summary>
        /// <value>
        /// The depth range far.
        /// </value>
        [Description("DepthRangeFar"), Category("Viewport attributes")]
        public double? DepthRangeFar
        {
            get { return depthRangeFar; }
            set
            {
                if (depthRangeFar != value)
                {
                    depthRangeFar = value;

                    NotifyPropertyChanged("DepthRangeFar");
                }
            }
        }

        #endregion Public Properties
    }
}
